#ifndef FFMPEG_MEDIAPLAYER_H
#define FFMPEG_MEDIAPLAYER_H

#include <pthread.h>
#include <jni.h>

#include "frame.h"
#include <android/log.h>
#include "global.h"
#include "Errors.h"
#include "libavfilter/avfiltergraph.h"
#include "libavfilter/buffersink.h"
#include "libavfilter/buffersrc.h"

#define FFMPEG_PLAYER_MAX_QUEUE_SIZE 50

using namespace android;

enum media_event_type {
    MEDIA_NOP               = 0, // interface test message
    MEDIA_PREPARED          = 1,
    MEDIA_PLAYBACK_COMPLETE = 2,
    MEDIA_BUFFERING_UPDATE  = 3,
    MEDIA_SEEK_COMPLETE     = 4,
    MEDIA_SET_VIDEO_SIZE    = 5,
    MEDIA_ERROR             = 100,
    MEDIA_INFO              = 200,
};

// Generic error codes for the media player framework.  Errors are fatal, the
// playback must abort.
//
// Errors are communicated back to the client using the
// MediaPlayerListener::notify method defined below.
// In this situation, 'notify' is invoked with the following:
//   'msg' is set to MEDIA_ERROR.
//   'ext1' should be a value from the enum media_error_type.
//   'ext2' contains an implementation dependant error code to provide
//          more details. Should default to 0 when not used.
//
// The codes are distributed as follow:
//   0xx: Reserved
//   1xx: Android Player errors. Something went wrong inside the MediaPlayer.
//   2xx: Media errors (e.g Codec not supported). There is a problem with the
//        media itself.
//   3xx: Runtime errors. Some extraordinary condition arose making the playback
//        impossible.
//
enum media_error_type {
    // 0xx
    MEDIA_ERROR_UNKNOWN = 1,
    // 1xx
    MEDIA_ERROR_SERVER_DIED = 100,
    // 2xx
    MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200,
    // 3xx
};


// Info and warning codes for the media player framework.  These are non fatal,
// the playback is going on but there might be some user visible issues.
//
// Info and warning messages are communicated back to the client using the
// MediaPlayerListener::notify method defined below.  In this situation,
// 'notify' is invoked with the following:
//   'msg' is set to MEDIA_INFO.
//   'ext1' should be a value from the enum media_info_type.
//   'ext2' contains an implementation dependant info code to provide
//          more details. Should default to 0 when not used.
//
// The codes are distributed as follow:
//   0xx: Reserved
//   7xx: Android Player info/warning (e.g player lagging behind.)
//   8xx: Media info/warning (e.g media badly interleaved.)
//
enum media_info_type {
    // 0xx
    MEDIA_INFO_UNKNOWN = 1,
    // 7xx
    // The video is too complex for the decoder: it can't decode frames fast
    // enough. Possibly only the audio plays fine at this stage.
    MEDIA_INFO_VIDEO_TRACK_LAGGING = 700,
    // 8xx
    // Bad interleaving means that a media has been improperly interleaved or not
    // interleaved at all, e.g has all the video samples first then all the audio
    // ones. Video is playing but a lot of disk seek may be happening.
    MEDIA_INFO_BAD_INTERLEAVING = 800,
    // The media is not seekable (e.g live stream).
    MEDIA_INFO_NOT_SEEKABLE = 801,
    // New media metadata is available.
    MEDIA_INFO_METADATA_UPDATE = 802,

    MEDIA_INFO_FRAMERATE_VIDEO = 900,
    MEDIA_INFO_FRAMERATE_AUDIO,
};



enum media_player_states {
    MEDIA_PLAYER_STATE_ERROR        = 0,
    MEDIA_PLAYER_IDLE               = 1 << 0,
    MEDIA_PLAYER_BEGIN_THREAD       = 1 << 1,
    MEDIA_PLAYER_INITIALIZED        = 1 << 2,
    MEDIA_PLAYER_PREPARING          = 1 << 3,
    MEDIA_PLAYER_PREPARED           = 1 << 4,
	MEDIA_PLAYER_DECODED            = 1 << 5,
    MEDIA_PLAYER_STARTED            = 1 << 6,
    MEDIA_PLAYER_PAUSED             = 1 << 7,
    MEDIA_PLAYER_STOPPED            = 1 << 8,
    MEDIA_PLAYER_PLAYBACK_COMPLETE  = 1 << 9
};

enum decode_type{
	DECODE_DISPLAY = 0,
	DECODE_PROCESS
};

class MediaPlayer
{
public:
    MediaPlayer(JNIEnv* env);
    ~MediaPlayer();
    void        setDataSource(const char *url);
    bool        start(int type);
    bool        stop();
    bool        pause();
	bool        isPlaying();
	bool        isBegin();
	bool        getVideoWidth(int *w);
	bool        getVideoHeight(int *h);
	bool        getDuration(int *msec);
	bool		prepare();
	void			setParamCount(int videoParam);
//    static  sp<IMemory>     decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
//    static  sp<IMemory>     decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
//    static  int             snoop(short *data, int len, int kind);
//            status_t        invoke(const Parcel& request, Parcel *reply);
//            status_t        setMetadataFilter(const Parcel& filter);
//            status_t        getMetadata(bool update_only, bool apply_filter, Parcel *metadata);
	bool        suspend();
	bool        resume();

	VideoFrame* processVideo(AVStream* stream);
	void treatSlap(VideoFrame* frame);
	void processSlap(AVFrame* frame,AVStream* stream);
	void decodeYuv(AVStream* stream);
	void getRGBData(AVStream* stream);
	void getRGBDataAndProcess(AVStream* stream);
	void setRestart();
	void setDecodeType(int type);
	void decodeYuvFilter(AVStream* stream);
	bool isBlackPicture(AVFrame* frame);
	void releaseResource();

	bool StartScope(const char* scopeFile, bool audioOn);
	bool EndScope();
	bool SlapPicture(const char* slapFile);
	void setStop(int isStop);


private:
	bool					connect();
	bool					prepareVideo();
	void 					closeVideo();
	static void*				startPlayer(void* ptr);

//	static void 				decodeVideo(VideoFrame* frame, unsigned char* param, AVFrame* avFrame);
//	static void 				decodeAudio(AudioFrame* frame, AVFrame* avFrame);

	void						decodeMovie(void* ptr);
	
	static void 				frameTreat(MovieFrame* frame);


	long getCurrTime();
	void avStreamFPSTimeBase(AVStream *st, float defaultTimeBase, float *pFPS, float *pTimeBase);
	int init_filters(const char *filters_descr);



	const char* 				mURL;
	double 						mTime;
	pthread_mutex_t             mLock;
	pthread_t					mPlayerThread;
	bool                        isFinish; //当前是否解码完毕
	int                         deltaTime;


    AVFormatContext*			mMovieFile;

    //filter related
    AVFilterContext *buffersink_ctx;
    AVFilterContext *buffersrc_ctx;
    AVFilterGraph *filter_graph;

    int 						mVideoStreamIndex;


    AVFrame*					mVideoFrame;
    AVFrame*                    mVideoFilterFrame;


	struct 	SwsContext* 		mVideoSwsContext;
	struct  SwsContext* 		mRgbToYuvContext;


	AVPicture					mVideoPicture;

	AVPicture                   mFilterPicture;


	float							mVideoFPS;


	float							mVideoTimeBase;



    void*                       mCookie;
    media_player_states         mCurrentState;

    int                         mCurrentPosition;
    int                         mSeekPosition;
    bool                        mPrepareSync;
    int                         mStreamType;
    bool                        mLoop;
    float                       mLeftVolume;
    float                       mRightVolume;
    int                         mVideoWidth;
    int                         mVideoHeight;

    int						 mVideoParamCount;

    //gmq add begin
       jbyteArray frameYDataArray;
       jbyteArray frameUDataArray;
       jbyteArray frameVDataArray;

       //gopro鐩告満閲囩敤濡備笅
       uint8_t * yData;
       uint8_t * uData;
       uint8_t * vData;

       jmethodID revokeFrameDataMethod;
       jbyteArray slapRGBDataArray;
       jbyteArray filterRGBDataArray;
       jmethodID revokeSlapDataMethod;
       jmethodID getFilterBmpDataMethod;//java层图像滤镜处理回调函数

       bool isIFrame;
       bool isFrameIncompleted;
       int decodeType;//解码方式，是送显还是解码进行滤镜处理

       //gmq add end

	 //录锟斤拷锟斤拷锟酵硷拷锟斤拷
	 bool mScopeOn;
	 bool findKeyFrame;
	 bool isRestart;//是否重新播放
	 bool mSlapOn;
	 char *mSlapFile;

	 int pts;
	 int dts;


};

static int check_interrupt(void *ctx);
static long lastDecodeTime;
static long lastConnectTime;
static int isConnect; //0鏈繛鎺�  1宸茶繛鎺�  2杩炴帴涓柇
static int mDuration;

int getCurrentTime()
{
  struct timeval tv;
  gettimeofday(&tv,NULL);
  return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}

#endif // FFMPEG_MEDIAPLAYER_H

